﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Gp.Scripts.Core.Res;
using QFramework;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Gp.Scripts.Core
{
    [AutoLoad]
    public class BattleSystem : BaseGameSystem, ICanSendCommand
    {
        private ResLoader _resLoader;
        private BaseUnit _template;

        public BattleSettleRoot BattleSettle => Global.GetSceneRoot<BattleSettleRoot>();

        public bool IsBattleStart => BattleSettle.IsBattleStarting;
        public BattleSettleRoot Level => BattleSettle;

        /// <summary>
        /// 当前回合单位。游戏开始后，一定会有一位当前回合单位。
        /// </summary>
        public BaseUnit CurrentUnit => BattleSettle?.CurrentUnit;


        public BattlePlayer CurrentPlayer => BattleSettle.CurrentPlayer;


        public RulesModel RulesModel => Global.Get<BattleSystemConfig>().RulesModel;

        public BattleCellGrid CellGrid => BattleSettle?.BattleCellGrid;
        
        public ITurnResolver TurnResolver => BattleSettle.TurnResolveController;

        public static int CombatantLayer { get; private set; }


        protected override void OnInit()
        {
            CombatantLayer = LayerMask.NameToLayer("BattleCharacter");

            // 初始化所有战斗单位
            // this.RegisterEvent<GlobalLoadEvent>(_ =>
            // {
            //     if (Level) this.SendCommand(new BattleEndCommand(BattleSettle));
            // });


            // var settle = UnityEngine.SceneManagement.SceneManager
            //     .GetActiveScene().GetRootGameObjects()
            //     .FirstOrDefault(o => PlayerConst.BattleSettleGameObjectName == o.name)
            //     ?.GetComponent<BattleSettle>();

            // settle ??= new GameObject(PlayerConst.BattleSettleGameObjectName, typeof(BattleSettle))
            //     .GetComponent<BattleSettle>();

            // this.BattleSettle = settle;
        }


        public void StartBattle()
        {
            Helpers.LogHelper.LogInfo(nameof(BattleSystem), "Battle Started");
            BattleSettle.BattleStart();
            BattleSettle.AddSequenceBuffer("战斗开始", Process());

            IEnumerator Process()
            {
                var transitionResult = BattleSettle.TurnResolveController.TransitionBattleStart();
                
                foreach (var unit in transitionResult.PlayableUnits())
                {
                    yield return unit.TriggerTurnStart();
                }
                if (transitionResult.NextPlayer == null) { throw new System.Exception("No Player"); }

                BattleSettle.CurrentPlayer = transitionResult.NextPlayer;
            }
        }


        public void NextTurn()
        {
            // if (BattleSettle.TurnResolveController.IsBlockEndTurn) return;
            // todo YHK: 处理重复调用该函数情况
            Level.AddSequenceBuffer("Turn End", TurnEndProcess());
            
            IEnumerator TurnEndProcess()
            {
                var units = BattleSettle.GetAllUnits().ToList();
                // 当前触发回合结束效果
                foreach (var unit in units) { yield return unit.TriggerTurnEnd(); }

                var transitionResult = TurnResolver.TransitionNextTurn();
                if (transitionResult.NextPlayer == null) { throw new System.Exception("No Next Player"); }
                BattleSettle.CurrentPlayer = transitionResult.NextPlayer;
                
                foreach (var unit in transitionResult.PlayableUnits()) { yield return unit.TriggerTurnStart(); }
            }
        }


        public void BlockInput(object blockKey)
        {
            // TODO YHK : implement this 
            BattleSettle.GameState = new GameStateBlockInput(blockKey, () => new GameStateWaitForInput());
        }

        

        public bool IsBlocked => BattleSettle.GameState is GameStateBlockInput;


        public void UnBlockInput(object blockKey)
        {
            BattleSettle.GameState = new GameStateBlockResume(blockKey);
        }

        /// <summary>
        /// 用于在block input 后恢复原有状态
        /// </summary>
        public void ToLastState()
        {
            if (!CurrentUnit || CurrentPlayer == null)
            {
                return;
            }

            // CurrentPlayer.ContinuePlay(entity);
        }


        private readonly HashSet<int> _deletingUnits = new();


        /// <summary>
        /// 摧毁某个单位
        /// </summary>
        /// <param name="unit"></param>
        /// <returns></returns>
        public IEnumerator DestroyUnit(BaseUnit unit)
        {
            if (IsUnitDestroyed(unit)) yield break;

            // 添加为死亡单位
            _deletingUnits.Add(unit.GetInstanceID());

            unit.TriggerEvent<Event_Unit.Death>();
            yield return unit.PlaySequence<DeathGestureSequence>();


            Level.AddSequenceBuffer("Destroy Unit --->\t" + unit.UnitName, DestroyUnitProcess());


            IEnumerator DestroyUnitProcess()
            {
                if (!unit) yield break;
                // 如果销毁单位为当前单位，结束回合
                if (BattleSettle.CurrentUnit == unit)
                {
                    BattleSettle.GameState = new GameStateWaitForInput();
                }

                // 检查游戏是否结束
                // 由于需要使用_deletingUnits.Contains判断单位销毁，
                // 因此此部分需要在_deletingUnits.Remove前执行
                if (CheckGameFinished())
                {
                    // 剩余单位标记为战斗结束
                    foreach (var u in GetValidUnits())
                    {
                        u.EndBattle();
                    }

                    MainArchitecture.Interface.SendCommand(new BattleEndCommand(BattleSettle));
                    BattleSettle.BattleEnd();
                }

                // var id = unit.GetInstanceID();
                // _deletingUnits.Remove(id);
                Object.Destroy(unit.EntityBehaviour);
            }
        }


        public bool CheckGameFinished()
        {
            var units = GetValidUnits().ToArray();
            if (units.All(u => IsUnitDestroyed(u) || u.PlayerNumber == PlayerConst.PlayerUnitNumber))
            {
                return true;
            }

            if (units.All(u => IsUnitDestroyed(u) || u.PlayerNumber == PlayerConst.AIUnitNumber))
            {
                return true;
            }

            return false;
        }


        public bool IsUnitDestroyed(BaseUnit unit)
        {
            return !unit || _deletingUnits.Contains(unit.GetInstanceID());
        }


        public bool IsUnitValid(BaseUnit unit)
        {
            return !IsUnitDestroyed(unit);
        }


        /// <summary>
        /// 获取当前所有参战且未死亡的单位
        /// </summary>
        /// <returns></returns>
        public IEnumerable<BaseUnit> GetValidUnits()
        {
            return BattleSettle.GetAllUnits().Where(u => !IsUnitDestroyed(u));
        }
    }
}

namespace Gp.Scripts.Core
{
    public class TurnResolveEvent
    {
        public BattlePlayer CurrentPlayer { get; }
        public TurnState TurnState { get; }

        public TurnResolveEvent(BattlePlayer currentPlayer, TurnState turnState)
        {
            CurrentPlayer = currentPlayer;
            TurnState     = turnState;
        }
    }
}